package com.sxt.service.impl;

import com.sxt.entity.Prod;
import com.sxt.entity.Prod.DeliveryModeVo;
import com.sxt.entity.ProdComm;
import com.sxt.entity.ProdTagReference;
import com.sxt.entity.Sku;
import com.sxt.mapper.ProdCommMapper;
import com.sxt.mapper.ProdMapper;
import com.sxt.mapper.ProdTagReferenceMapper;
import com.sxt.mapper.SkuMapper;
import com.sxt.model.ProdSolrDto;
import com.sxt.model.ProdSolrDto.ProdSolrDtoBuilder;
import com.sxt.model.ShopCartItem;
import com.sxt.service.ProdService;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * <p>
 * 商品 服务实现类
 * </p>
 *
 * @author liangtiandong
 * @since 2019-12-17
 */
@Service(timeout = 10000, retries = 0)
@Slf4j
public class ProdServiceImpl extends ServiceImpl<ProdMapper, Prod> implements ProdService {

	@Autowired
	private ProdMapper prodMapper;

	@Autowired
	private ProdTagReferenceMapper prodTagReferenceMapper;

	@Autowired
	private SkuMapper skuMapper;

	@Autowired
	private ProdCommMapper prodCommon;
	
	private static String PROD_STOCK = "stock:prod:" ;
	
	@PostConstruct
	public void init () {
		// 最好是分页导入，多线程没有必要，因为redis 是单线程的
		// 参考solr的导入完成对库存的导入
		
	}

	@Override
	public IPage<Prod> findByPage(Page<Prod> page, Prod prod) {
		log.info("分页查询{},{}", page.getCurrent(), page.getSize());
		return prodMapper.selectPage(page, new LambdaQueryWrapper<Prod>().
				// 字段-> 返回一个true /false 若为true，则查询该字段，false 不查询
				select(Prod.class, filed -> !filed.getProperty().equals("content")). // jdk8 Lambda 表达式
				like(StringUtils.hasText(prod.getProdName()), Prod::getProdName, prod.getProdName()).
				// Status 1 -1（删除） 0
				eq(prod.getStatus() != null, Prod::getStatus, prod.getStatus())
				// status = 1 /0 能显示出来，=-1 是删除了的，不能显示
				.ne(prod.getStatus() == null, Prod::getStatus, -1));
	}

	/**
	 * 新增一个商品，他花费的时间较长，最好设置超时时间，和重试次数
	 */
	@Transactional // 全部的成功或失败
	@Override
	public boolean save(Prod entity) {
		Assert.notNull(entity, "新增的商品不能为null");
		log.info("新增商品{}", JSONUtil.toJsonPrettyStr(entity));
		/**
		 * 商品的属性构造
		 */
		entity.setShopId(1L);
		entity.setSoldNum(0);
		DeliveryModeVo deliveryModeVo = entity.getDeliveryModeVo();
		entity.setDeliveryMode(JSONUtil.toJsonStr(deliveryModeVo));
		entity.setCreateTime(LocalDateTime.now());
		entity.setUpdateTime(LocalDateTime.now());
		if (entity.getStatus() == 1) {
			entity.setPutawayTime(LocalDateTime.now()); // 上架的时间
		}
		entity.setVersion(1);
		boolean save = super.save(entity); // 商品的新增
		if (save) {
			addProdTag(entity);
			addProdSku(entity);
		}
		// 商品和分组的关系是多对多：中间表
		// 商品和sku，一个商品，有多个sku
		return save;
	}

	/**
	 * 商品的sku 信息的新增
	 * 
	 * @param entity
	 */
	private void addProdSku(Prod entity) {
		List<Sku> skuList = entity.getSkuList();
		if (skuList != null && !skuList.isEmpty()) {
			for (Sku sku : skuList) {
				// 构建sku的属性
				sku.setProdId(entity.getProdId());
				sku.setUpdateTime(LocalDateTime.now());
				sku.setRecTime(LocalDateTime.now());
				sku.setIsDelete(0);
				// sku.setStatus(1); 禁用和启用，在前端里面有值
				sku.setVersion(1);
				skuMapper.insert(sku);
			}
		}

	}

	/**
	 * 商品的标签数据新增 多对多的关系
	 * 
	 * @param entity
	 */
	private void addProdTag(Prod entity) {
		List<Long> tagList = entity.getTagList();
		if (tagList != null && !tagList.isEmpty()) {
			for (Long tagId : tagList) {
				ProdTagReference prodTagReference = new ProdTagReference();
				// 中间表的数据
				prodTagReference.setProdId(entity.getProdId());
				prodTagReference.setTagId(tagId);
				prodTagReference.setStatus(1);
				prodTagReference.setCreateTime(LocalDateTime.now());
				prodTagReference.setShopId(1L);
				prodTagReferenceMapper.insert(prodTagReference);
			}
		}

	}

	/**
	 * 回显商品的数据
	 */
	@Override
	public Prod getById(Serializable id) {
		Prod prod = super.getById(id);
		List<Sku> skuList = getSkuList(id);
		prod.setSkuList(skuList);
		List<Long> tagList = getTagList(id);
		prod.setTagList(tagList);
		return prod;
	}

	/**
	 * 根据商品的id查询该商品参与的所有分组信息
	 * 
	 * @param id
	 * @return
	 */
	private List<Long> getTagList(Serializable id) {
		List<Object> tagObjIds = prodTagReferenceMapper.selectObjs(new LambdaQueryWrapper<ProdTagReference>()
				.select(ProdTagReference::getTagId).eq(ProdTagReference::getProdId, id));
		if (tagObjIds == null) {
			return Collections.emptyList();
		}
		List<Long> tagList = new ArrayList<Long>(tagObjIds.size());
		for (Object tagObjId : tagObjIds) {
			tagList.add(Long.valueOf(tagObjId.toString()));
		}
		return tagList;
	}

	/**
	 * 根据商品的id 查询sku 的列表
	 * 
	 * @param id
	 * @return
	 */
	private List<Sku> getSkuList(Serializable id) {
		List<Sku> skuList = skuMapper.selectList(new LambdaQueryWrapper<Sku>().eq(Sku::getProdId, id));
		return skuList == null ? Collections.emptyList() : skuList;
	}

	@Transactional // 合并事务，优化性能
	public boolean updateById(Prod entity) {

		entity.setUpdateTime(LocalDateTime.now());
		if (entity.getStatus() == 1) {
			entity.setPutawayTime(LocalDateTime.now());
		}
		boolean updateById = super.updateById(entity);
		if (updateById) {
			handlerTag(entity);
			handlerSku(entity);
		}
		return updateById;
	}

	/**
	 * 先删除之前的sku ，新增修改的sku 值
	 * 
	 * @param entity
	 */
	private void handlerSku(Prod entity) {
		// 删除旧制的操作
		skuMapper.delete(new LambdaQueryWrapper<Sku>().eq(Sku::getProdId, entity.getProdId()));
		addProdSku(entity);
	}

	/**
	 * 先删除，再新增
	 * 
	 * @param entity
	 */
	private void handlerTag(Prod entity) {
		// 删除旧值
		prodTagReferenceMapper
		.delete(new LambdaQueryWrapper<ProdTagReference>().eq(ProdTagReference::getProdId, entity.getProdId()));
		// 添加新的值
		addProdTag(entity);
	}

	@Transactional
	@Override
	public boolean removeById(Serializable id) {
		Prod prod = new Prod(); // 在mp 里面，当修改数据时，数据里面的字段若为null ，他不参与修改的过程，属于安全的修改
		prod.setProdId(Long.valueOf(id + ""));
		prod.setStatus(-1);
		int updateById = prodMapper.updateById(prod);
		if (updateById > 0) {
			// 删除sku 和tag
			prodTagReferenceMapper
			.delete(new LambdaQueryWrapper<ProdTagReference>().eq(ProdTagReference::getProdId, id));
			skuMapper.delete(new LambdaQueryWrapper<Sku>().eq(Sku::getProdId, id));
		}
		return updateById > 0;
	}

	@Override
	public Prod getProdPicAndProdName(Long id) {
		log.info("查询商品{}的名称和图片");
		return prodMapper.selectOne(
				new LambdaQueryWrapper<Prod>().select(Prod::getProdName, Prod::getPic).eq(Prod::getProdId, id));
	}

	/**
	 *
	 * 分页查询商品的数据
	 */
	//TODO
	@Override
	public List<ProdSolrDto> listProd(int current, int size,Date t1,Date t2) {
		Page<Prod> page = new Page<Prod>(current, size);
		IPage<Prod> prodPageData = prodMapper.selectPage(page,
				new LambdaQueryWrapper<Prod>().select(Prod.class, (filed) -> {
					return !("content".equals(filed.getColumn()));
				}).
				eq(Prod::getStatus, 1).
				between((t1!=null && t2!=null), Prod::getUpdateTime, t1,t2)
				);
		List<Prod> prodList = prodPageData.getRecords();
		if (prodList == null || prodList.isEmpty()) {
			return Collections.emptyList();
		}
		List<ProdSolrDto> prodSolrDto = new ArrayList<ProdSolrDto>(prodList.size());
		for (Prod prod : prodList) {
			prodSolrDto.add(prod2ProdSolrDto(prod)); // 将prod2ProdSolrDto
		}
		return prodSolrDto;
	}

	/**
	 * 将prod 2 prodSolrDto
	 * 
	 * @param prod
	 * @return
	 */
	private ProdSolrDto prod2ProdSolrDto(Prod prod) {
		List<Long> tagList = getProdTags(prod.getProdId());
		Integer countTotal = prodCommon
				.selectCount(new LambdaQueryWrapper<ProdComm>().eq(ProdComm::getProdId, prod.getProdId()));
		long praiseNumber = countTotal == null ? 0 : countTotal;

		Integer positiveNum = prodCommon.selectCount(new LambdaQueryWrapper<ProdComm>()
				.eq(ProdComm::getProdId, prod.getProdId()).eq(ProdComm::getEvaluate, 0));
		long positiveSim = positiveNum == null ? 0 : positiveNum;
		double positiveRatingDou = ((praiseNumber == 0L) ? 0.00
				: (positiveSim == 0L) ? 0.00 : positiveSim / praiseNumber)*100; // 0.127979789 *100 == 12.7979789
		// 计算价格,计算总价,好评,都需要使用BigDecimal
		BigDecimal positiveRating = new BigDecimal(positiveRatingDou).setScale(2,BigDecimal.ROUND_HALF_UP);
		return ProdSolrDto.builder().id(prod.getProdId().toString()) // 商品的id
				.prodName(prod.getProdName()) // 商品的名称
				.price(prod.getPrice()) // 商品的价格BigDecimal->pdouble 类型
				.categoryId(prod.getCategoryId()) // 商品的分类id
				.pic(prod.getPic()) // 商品的主图
				.brief(prod.getBrief()) // 商品的买点
				.soldNum(prod.getSoldNum() == null ? 0L : prod.getSoldNum()) // 商品的销量
				.praiseNumber(praiseNumber) // 评论数
				.positiveRating(positiveRating) // 好评率
				.tagList(tagList).build(); // 商品的标签
	}

	private List<Long> getProdTags(Long prodId) {
		List<Object> tagObjes = prodTagReferenceMapper.selectObjs(new LambdaQueryWrapper<ProdTagReference>().
				select(ProdTagReference::getTagId)
				.eq(ProdTagReference::getProdId, prodId)
				);
		if(tagObjes==null || tagObjes.isEmpty()) {
			return Collections.emptyList() ;
		}
		List<Long> tagObjs = new ArrayList<Long>();
		//		tagObjes.forEach((k)->tagObjs.add(Long.valueOf(object.toString()));
		for (Object object : tagObjes) {
			tagObjs.add(Long.valueOf(object.toString()));
		}
		return tagObjs;
	}

	public static void main(String[] args) {
		BigDecimal positiveRating = new BigDecimal(12.7979789).setScale(2, BigDecimal.ROUND_HALF_UP);
		System.out.println(positiveRating);
	}

	/**
	 * 得到总条数
	 */
	//TODO
	@Override
	public int countProd(Date t1,Date t2) {
		Integer total = prodMapper.selectCount(
				new LambdaQueryWrapper<Prod>().eq(Prod::getStatus, 1).
				between((t1!=null && t2!=null), Prod::getUpdateTime, t1,t2)
				);
		return total==null ? 0 : total;
	}

	/**
	 * 商品的库存--
	 */
	@Override
	public void decsStock(List<ShopCartItem> cartItems) {
		if(cartItems==null || cartItems.isEmpty()) {
			return ;
		}
		for (ShopCartItem shopCartItem : cartItems) {
			Long prodId = shopCartItem.getProdId();
			Integer prodCount = shopCartItem.getProdCount();
			Prod prod = prodMapper.selectOne(new LambdaQueryWrapper<Prod>().
					select(Prod::getTotalStocks).eq(Prod::getProdId, prodId)) ;
			Integer dbStock = prod.getTotalStocks();
			Integer remainStock = 0 ; ;
			if((remainStock=(dbStock-prodCount))<0) {
				throw new RuntimeException("库存不足");
			}
			prod.setProdId(prodId) ;
			prod.setTotalStocks(remainStock) ;
			prod.setUpdateTime(LocalDateTime.now()) ;
			prodMapper.updateById(prod) ;
		}
	}
}
